package top.purity.framework.web.filter;

import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.router.SaHttpMethod;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import top.purity.framework.common.GlobalConstant;
import top.purity.framework.common.TenantContextHolder;
import top.purity.framework.common.UserContextHolder;
import top.purity.framework.common.result.GlobalRespCode;
import top.purity.framework.common.result.RespResult;

import java.util.List;

/**
 * @version 1.0
 * @Author Lmh
 * @Description
 * @CreateTime 2023-09-21 19:38
 */
@Configuration
@Slf4j
public class SaTokenFilter {

    @Bean
    public SaServletFilter saServletFilter() {
        return new SaServletFilter()
            .addInclude("/**")
            .addExclude("/favicon.ico",
                    "/sso/**", "/*/sso/**", GlobalConstant.RPC_PREFIX + "/**")
            .setAuth(auth -> {
                log.info("---------- 进入Sa-Token全局认证 -----------");
                SaRequest request = SaHolder.getRequest();

                String header = request.getHeader(GlobalConstant.AUTH_HEADER);
                if (StrUtil.isBlank(header)) {
                    SaRouter.back(JSONUtil.toJsonStr(RespResult.error(GlobalRespCode.UN_LOGIN)));
                }

                // 解析 login id 格式为 user id + "_" + tenant id
                Object loginId = StpUtil.getLoginIdByToken(header);
                if (ObjUtil.isNull(loginId)) {
                    SaRouter.back(JSONUtil.toJsonStr(RespResult.error(GlobalRespCode.LOGIN_EXPIRE)));
                }

                // 设置租户id，用户id
                List<String> split = StrUtil.split((String) loginId, GlobalConstant.LOGIN_ID_SPLIT);
                Long userId = Long.valueOf(split.get(GlobalConstant.LOGIN_ID_INDEX_USER));
                UserContextHolder.setUserId(userId);
                Long tenantId = Long.valueOf(split.get(GlobalConstant.LOGIN_ID_INDEX_TENANT));
                TenantContextHolder.setTenantId(tenantId);
                TenantContextHolder.setIgnore(false);

                log.info("---------- 当前租户：{}，用户：{} -----------", tenantId, userId);

                SaRouter.stop();
            })
            .setError(error -> {
                log.error("---------- 进入Sa-Token异常处理 -----------", error);
                UserContextHolder.clear();
                TenantContextHolder.clear();
                String message = error.getMessage();
                return RespResult.error(message);
            })
            // 前置函数：在每次认证函数之前执行（BeforeAuth 不受 includeList 与 excludeList 的限制，所有请求都会进入）
            .setBeforeAuth(before -> {
                SaRequest request = SaHolder.getRequest();
                String requestPath = request.getRequestPath();
                log.info("---------- 进入Sa-Token请求前置处理 : {} -----------", requestPath);

//                SaResponse response = SaHolder.getResponse();
//                response.setHeader("Access-Control-Allow-Origin", "*");
//                response.setHeader("Access-Control-Allow-Methods", "*");
//                response.setHeader("Access-Control-Allow-Headers", "*");
//                response.setHeader("Access-Control-Max-Age", "3600");
//                response.setHeader("Content-Type", "application/json;charset=utf-8");

                // 因为存在路径白名单，所以先设置一下忽略租户id
                TenantContextHolder.setIgnore(true);

                SaRouter.match(SaHttpMethod.OPTIONS).stop();
            });
    }
}
